﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace iNet.Media.Imaging.Png
{
	/// <summary>
	/// 支援 PNG tExt 的中繼資料基底類別。
	/// </summary>
	public class PngMetadataBase : ImageMetadataBase, ITextualMetadata
	{
		#region 靜態欄位
		/// <summary>
		/// 適用於 IMetadata.Author 屬性的中繼資料項目名稱。
		/// </summary>
		public static readonly string AuthorItemName = "Author";
		/// <summary>
		/// 適用於 IMetadata.Comment 屬性的中繼資料項目名稱。
		/// </summary>
		public static readonly string CommentItemName = "Comment";
		/// <summary>
		/// 適用於 IMetadata.Copyright 屬性的中繼資料項目名稱。
		/// </summary>
		public static readonly string CopyrightItemName = "Copyright";
		/// <summary>
		/// 適用於 IMetadata.CreationTime 屬性的中繼資料項目名稱。
		/// </summary>
		public static readonly string CreationTimeItemName = "Creation Time";
		/// <summary>
		/// 適用於 IMetadata.Software 屬性的中繼資料項目名稱。
		/// </summary>
		public static readonly string SoftwareItemName = "Software";
		/// <summary>
		/// 適用於 IMetadata.Title 屬性的中繼資料項目名稱。
		/// </summary>
		public static readonly string TitleItemName = "Title";
		#endregion
		#region 欄位
		List<TextualMetadataItem> _Items = new List<TextualMetadataItem>();
		IList<TextualMetadataItem> _TextualMetadataItems;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 PngMetadataBase 執行個體。
		/// </summary>
		public PngMetadataBase()
		{
			_TextualMetadataItems = _Items;
		}
		/// <summary>
		/// 初始化新的 PngMetadataBase 執行個體。
		/// </summary>
		/// <param name="items">文字中繼資料項目列表。</param>
		/// <param name="isReadOnly">是否為唯讀。</param>
		public PngMetadataBase(IEnumerable<TextualMetadataItem> items, bool isReadOnly)
			: base(null, isReadOnly)
		{
			if (items != null)
				_Items.AddRange(items);
			_TextualMetadataItems = (isReadOnly ? new ReadOnlyCollection<TextualMetadataItem>(_Items) : (IList<TextualMetadataItem>)_Items);
		}
		/// <summary>
		/// 初始化新的 PngMetadataBase 執行個體。
		/// </summary>
		/// <param name="template">範本中繼資料。</param>
		/// <param name="isReadOnly">是否為唯讀。</param>
		public PngMetadataBase(IMetadata template, bool isReadOnly)
			: base(template, isReadOnly)
		{
			_TextualMetadataItems = (isReadOnly ? new ReadOnlyCollection<TextualMetadataItem>(_Items) : (IList<TextualMetadataItem>)_Items);
		}
		#endregion
		#region Author
		/// <summary>
		/// 取得或設定影像的作者。
		/// </summary>
		public override string[] Authors
		{
			get
			{
				return this.GetValueAsStringArray(AuthorItemName);
			}
			set
			{
				if (this.IsReadOnly)
					throw new InvalidOperationException();
				this.UpdateItem(AuthorItemName, value);
			}
		}
		#endregion
		#region Clone
		/// <summary>
		/// 建立可修改的 PngMetadataBase 副本。
		/// </summary>
		/// <returns>PngMetadataBase 副本。</returns>
		public override object Clone()
		{
			return new PngMetadataBase(_Items, false);
		}
		#endregion
		#region Comment
		/// <summary>
		/// 取得或設定影像的註解文字。
		/// </summary>
		public override string Comment
		{
			get
			{
				return this.GetValue(CommentItemName);
			}
			set
			{
				if (this.IsReadOnly)
					throw new InvalidOperationException();
				this.UpdateItem(CommentItemName, value);
			}
		}
		#endregion
		#region CopyFrom
		/// <summary>
		/// 從指定的中繼資料複製屬性。
		/// </summary>
		/// <param name="metadata">指定的中繼資料。</param>
		/// <exception cref="InvalidOperationException">中繼資料為唯讀。</exception>
		public override void CopyFrom(IMetadata metadata)
		{
			//確認狀態
			if (this.IsReadOnly)
				throw new InvalidOperationException();

			//複製屬性
			if (metadata != null && metadata != this)
			{
				//複製 Textual Metadata
				if (metadata is ITextualMetadata)
					_Items.AddRange((metadata as ITextualMetadata).TextualMetadataItems);

				//複製一般屬性
				this.Authors = metadata.Authors;
				this.Comment = metadata.Comment;
				this.Copyright = metadata.Copyright;
				this.CreationTime = metadata.CreationTime;
				this.Software = metadata.Software;
				this.Title = metadata.Title;
			}
		}
		#endregion
		#region Copyright
		/// <summary>
		/// 取得或設定影像的版權資訊。
		/// </summary>
		public override string Copyright
		{
			get
			{
				return this.GetValue(CopyrightItemName);
			}
			set
			{
				if (this.IsReadOnly)
					throw new InvalidOperationException();
				this.UpdateItem(CopyrightItemName, value);
			}
		}
		#endregion
		#region ConvertFromDateTime
		string ConvertFromDateTime(DateTime value)
		{
			return value.ToString("yyyy:MM:dd HH:mm:ss");
		}
		#endregion
		#region ConvertToDateTime
		DateTime? ConvertToDateTime(string value)
		{
			StringBuilder buffer = new StringBuilder(value);
			int count = 0;
			for (int i = 0; i < buffer.Length && count < 2; i++)
			{
				if (buffer[i] == ':')
				{
					buffer[i] = '/';
					count++;
				}
			}
			DateTime dateTime;
			if (count >= 2 && DateTime.TryParse(buffer.ToString(), out dateTime))
				return dateTime;
			return null;
		}
		#endregion
		#region CreationTime
		/// <summary>
		/// 取得或設定影像建立時間。
		/// </summary>
		public override DateTime? CreationTime
		{
			get
			{
				return this.GetValueAsDateTime(CreationTimeItemName);
			}
			set
			{
				if (this.IsReadOnly)
					throw new InvalidOperationException();
				this.UpdateItem(CreationTimeItemName, value);
			}
		}
		#endregion
		#region FindItem
		TextualMetadataItem FindItem(string name)
		{
			for (int i = _Items.Count - 1; i >= 0; --i)
			{
				TextualMetadataItem item = _Items[i];
				if (item != null && item.Name == name)
					return item;
			}
			return null;
		}
		#endregion
		#region GetAsReadOnly
		/// <summary>
		/// 取得唯讀的 PngMetadataBase。
		/// </summary>
		/// <returns>唯讀的 PngMetadataBase。</returns>
		public override IMetadata GetAsReadOnly()
		{
			if (this.IsReadOnly)
				return this;
			return new PngMetadataBase(_Items, true);
		}
		#endregion
		#region GetValue
		string GetValue(string name)
		{
			TextualMetadataItem item = this.FindItem(name);
			return (item != null ? item.Value : null);
		}
		#endregion
		#region GetValueAsDateTime
		DateTime? GetValueAsDateTime(string name)
		{
			//搜尋項目
			TextualMetadataItem item = this.FindItem(name);
			if (item == null)
				return null;

			//轉成日期時間
			return this.ConvertToDateTime(item.Value);
		}
		#endregion
		#region GetValueAsStringArray
		string[] GetValueAsStringArray(string name)
		{
			//取得字串
			string value = this.GetValue(name);
			if (value == null)
				return null;

			//轉成字串陣列
			return value.Split(';');
		}
		#endregion
		#region RemoveItems
		int RemoveItems(string name)
		{
			return _Items.RemoveAll((item) =>
				{
					return (item == null || item.Name == name);
				});
		}
		#endregion
		#region Software
		/// <summary>
		/// 取得或設定製作影像的軟體名稱。
		/// </summary>
		public override string Software
		{
			get
			{
				return this.GetValue(SoftwareItemName);
			}
			set
			{
				if (this.IsReadOnly)
					throw new InvalidOperationException();
				this.UpdateItem(SoftwareItemName, value);
			}
		}
		#endregion
		#region TextualMetadataItems
		/// <summary>
		/// 取得文字中繼資料項目列表。
		/// </summary>
		public IList<TextualMetadataItem> TextualMetadataItems
		{
			get 
			{
				return _TextualMetadataItems;
			}
		}
		#endregion
		#region Title
		/// <summary>
		/// 取得或設定影像的標題。
		/// </summary>
		public override string Title
		{
			get
			{
				return this.GetValue(TitleItemName);
			}
			set
			{
				if (this.IsReadOnly)
					throw new InvalidOperationException();
				this.UpdateItem(TitleItemName, value);
			}
		}
		#endregion
		#region UpdateItem
		void UpdateItem(string name, string value)
		{
			this.RemoveItems(name);
			if (value != null)
				_Items.Add(new TextualMetadataItem(name, value));
		}
		void UpdateItem(string name, DateTime? value)
		{
			this.RemoveItems(name);
			if (value != null)
				_Items.Add(new TextualMetadataItem(name, this.ConvertFromDateTime(value.Value)));
		}
		void UpdateItem(string name, string[] value)
		{
			this.RemoveItems(name);
			if (value != null && value.Length > 0)
			{
				StringBuilder buffer = new StringBuilder(value[0]);
				for (int i = 1; i < value.Length; ++i)
					buffer.Append(";" + value[i]);
				_Items.Add(new TextualMetadataItem(name, buffer.ToString()));
			}
		}
		#endregion
	}
}
